package com.qyx.pmpucat.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.mybatisflex.core.query.QueryWrapper;
import com.qyx.pmpucat.common.exception.ClientException;
import com.qyx.pmpucat.dto.ExcelQuestionDto;
import com.qyx.pmpucat.dto.QuestionDTO;
import com.qyx.pmpucat.dto.QuestionOptionDTO;
import com.qyx.pmpucat.entity.OptionCategory;
import com.qyx.pmpucat.entity.Question;
import com.qyx.pmpucat.entity.Questionnaire;
import com.qyx.pmpucat.mapper.QuestionMapper;
import com.qyx.pmpucat.mapper.QuestionnaireMapper;
import com.qyx.pmpucat.service.OptionCategoryService;
import com.qyx.pmpucat.service.QuestionService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.qyx.pmpucat.entity.table.QuestionTableDef.QUESTION;

/**
 * 问题服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class QuestionServiceImpl implements QuestionService {

    private static final String QUESTION_CACHE_KEY_PREFIX = "questions:questionnaire:";
    
    private final QuestionMapper questionMapper;
    private final QuestionnaireMapper questionnaireMapper;
    private final OptionCategoryService optionCategoryService;
    private final RedisTemplate<String, Object> redisTemplate;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createQuestion(QuestionDTO questionDTO) {
        // 检查问卷是否存在
        Long questionnaireId = questionDTO.getQuestionnaireId();
        if (questionnaireId == null) {
            throw new ClientException("问卷ID不能为空");
        }

        Questionnaire questionnaire = questionnaireMapper.selectOneById(questionnaireId);
        if (questionnaire == null) {
            throw new ClientException("问卷不存在");
        }

        // 已发布的问卷不能添加问题
        if (questionnaire.getStatus() == 1) {
            throw new ClientException("已发布的问卷不能添加问题");
        }

        // 查询该问卷下最大的排序号
        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.where(QUESTION.QUESTIONNAIRE_ID.eq(questionnaireId));
        queryWrapper.orderBy(QUESTION.SORT.desc());
        queryWrapper.limit(1);
        Question lastQuestion = questionMapper.selectOneByQuery(queryWrapper);
        int sort = 1;
        if (lastQuestion != null) {
            sort = lastQuestion.getSort() + 1;
        }

        // 创建问题
        Question question = new Question();
        BeanUtils.copyProperties(questionDTO, question);
        question.setSort(sort);

        // 设置创建人信息
        question.setCreateBy(StpUtil.getLoginIdAsLong());

        // 设置问题选项
        List<Question.QuestionOption> options = convertOptions(questionDTO.getOptions());
        question.setOptions(options);

        // 保存问题
        questionMapper.insert(question);

        // 清除问卷题目缓存
        deleteQuestionCache(questionnaireId);

        return question.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateQuestion(QuestionDTO questionDTO) {
        // 检查问题是否存在
        Long questionId = questionDTO.getId();
        if (questionId == null) {
            throw new ClientException("问题ID不能为空");
        }

        Question existQuestion = questionMapper.selectOneById(questionId);
        if (existQuestion == null) {
            throw new ClientException("问题不存在");
        }

        // 检查问卷是否已发布
        Questionnaire questionnaire = questionnaireMapper.selectOneById(existQuestion.getQuestionnaireId());
        if (questionnaire != null && questionnaire.getStatus() == 1) {
            throw new ClientException("已发布的问卷不能修改问题");
        }

        // 更新问题信息
        Question question = new Question();
        BeanUtils.copyProperties(questionDTO, question);

        // 设置问题选项
        List<Question.QuestionOption> options = convertOptions(questionDTO.getOptions());
        question.setOptions(options);

        // 更新问题
        questionMapper.update(question);

        // 清除问卷题目缓存
        deleteQuestionCache(existQuestion.getQuestionnaireId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteQuestion(Long id) {
        // 检查问题是否存在
        Question existQuestion = questionMapper.selectOneById(id);
        if (existQuestion == null) {
            throw new ClientException("问题不存在");
        }

        // 检查问卷是否已发布
        Questionnaire questionnaire = questionnaireMapper.selectOneById(existQuestion.getQuestionnaireId());
        if (questionnaire != null && questionnaire.getStatus() == 1) {
            throw new ClientException("已发布的问卷不能删除问题");
        }

        // 删除问题（选项会作为问题的一部分一起删除）
        questionMapper.deleteById(id);

        // 清除问卷题目缓存
        deleteQuestionCache(existQuestion.getQuestionnaireId());
    }

    @Override
    public Question getQuestionDetail(Long id) {
        // 检查问题是否存在
        Question question = questionMapper.selectOneWithRelationsById(id);
        if (question == null) {
            throw new ClientException("问题不存在");
        }

        return question;
    }

    @Override
    public List<Question> getQuestionsByQuestionnaireId(Long questionnaireId) {
        // 检查问卷是否存在
        Questionnaire questionnaire = questionnaireMapper.selectOneById(questionnaireId);
        if (questionnaire == null) {
            throw new ClientException("问卷不存在");
        }

        // 查询问题列表
        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.where(QUESTION.QUESTIONNAIRE_ID.eq(questionnaireId));
        queryWrapper.orderBy(QUESTION.SORT.asc());
        List<Question> questions = questionMapper.selectListWithRelationsByQuery(queryWrapper);

        return questions;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importQuestion(MultipartFile file, Long questionnaireId) {
        if (file == null || file.isEmpty()) {
            throw new ClientException("文件不能为空");
        }

        if (questionnaireId == null) {
            throw new ClientException("问卷ID不能为空");
        }

        // 检查问卷是否存在且未发布
        Questionnaire questionnaire = questionnaireMapper.selectOneById(questionnaireId);
        if (questionnaire == null) {
            throw new ClientException("问卷不存在");
        }


        try (InputStream inputStream = file.getInputStream()) {
            // 读取Excel文件
            ExcelReader reader = ExcelUtil.getReader(inputStream);

            // 读取数据并转换为ExcelQuestionDto列表
            List<ExcelQuestionDto> excelDataList = reader.readAll(ExcelQuestionDto.class);

            if (CollUtil.isEmpty(excelDataList)) {
                throw new ClientException("Excel文件中没有数据");
            }

            // 统计导入结果
            int successCount = 0;
            int failCount = 0;
            StringBuilder errorMessages = new StringBuilder();

            for (int i = 0; i < excelDataList.size(); i++) {
                try {
                    ExcelQuestionDto excelData = excelDataList.get(i);

                    // 数据验证
                    validateExcelData(excelData, i + 2, questionnaireId); // i+2 因为Excel行号从1开始，且第一行是标题

                    // 转换并保存问题
                    Question question = convertExcelToQuestion(excelData, questionnaireId);
                    questionMapper.insert(question);

                    successCount++;
                } catch (Exception e) {
                    failCount++;
                    errorMessages.append("第").append(i + 2).append("行：").append(e.getMessage()).append("；");
                    log.error("导入第{}行数据失败：{}", i + 2, e.getMessage(), e);
                }
            }

            // 如果有成功导入的题目，清除问卷题目缓存
            if (successCount > 0) {
                deleteQuestionCache(questionnaireId);
            }

            // 构建返回结果
            String result = String.format("导入完成！成功导入%d条，失败%d条", successCount, failCount);
            if (failCount > 0) {
                result += "。失败原因：" + errorMessages.toString();
            }

            return result;

        } catch (IOException e) {
            log.error("读取Excel文件失败：{}", e.getMessage(), e);
            throw new ClientException("读取Excel文件失败：" + e.getMessage());
        } catch (Exception e) {
            log.error("导入Excel失败：{}", e.getMessage(), e);
            throw new ClientException("导入Excel失败：" + e.getMessage());
        }
    }

    @Override
    public ResponseEntity<byte[]> exportQuestionsToExcel(Long questionnaireId, HttpServletResponse response) {
        // 检查问卷是否存在
        Questionnaire questionnaire = questionnaireMapper.selectOneById(questionnaireId);
        if (questionnaire == null) {
            throw new ClientException("问卷不存在");
        }

        // 查询问题列表
        List<Question> questions = getQuestionsByQuestionnaireId(questionnaireId);
        //查询出问题对应的选项分类
        Map<Long, List<String>> optionMap = optionCategoryService.getAllOptionCategories().stream()
                .collect(Collectors.toMap(OptionCategory::getId,
                        i -> i.getOptions().stream().map(OptionCategory.Option::getLabel).toList()));


        // 转换为Excel数据格式
        List<ExcelQuestionDto> excelDataList = questions.stream()
                .map(i -> convertQuestionToExcel(i, optionMap))
                .collect(Collectors.toList());

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            // 创建Excel写入器
            ExcelWriter writer = ExcelUtil.getWriter(true);

            // 写入数据
            writer.write(excelDataList, true);

            // 输出到字节数组
            writer.flush(outputStream);
            writer.close();

            byte[] byteArray = outputStream.toByteArray();

            // 设置文件名
            String fileName = questionnaire.getTitle() + "_" + System.currentTimeMillis() + ".xlsx";
            return buildDownloadResponse(byteArray, fileName);
        } catch (IOException e) {
            log.error("导出Excel失败：{}", e.getMessage(), e);
            throw new ClientException("导出Excel失败：" + e.getMessage());
        }


    }

    private ResponseEntity<byte[]> buildDownloadResponse(byte[] bytes, String fileName) {
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" +
                URLEncoder.encode(fileName, StandardCharsets.UTF_8));
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        return ResponseEntity.ok()
                .headers(headers)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(bytes);
    }

    /**
     * 验证Excel数据
     */
    private void validateExcelData(ExcelQuestionDto excelData, int rowNumber, Long questionnaireId) {
        if (StrUtil.isBlank(excelData.getTitle())) {
            throw new ClientException("问题标题不能为空");
        }
    }

    /**
     * 将Excel数据转换为Question对象
     */
    private Question convertExcelToQuestion(ExcelQuestionDto excelData, Long questionnaireId) {
        Question question = new Question();

        // 基本信息
        question.setTitle(excelData.getTitle());
        question.setAlphj(excelData.getAlphj());
        question.setQuestionnaireId(questionnaireId);
        question.setOptionCategoryId(excelData.getOptionCategoryId());

        // 设置排序号
        if (excelData.getSort() != null) {
            question.setSort(excelData.getSort());
        } else {
            // 查询该问卷下最大的排序号
            QueryWrapper queryWrapper = QueryWrapper.create();
            queryWrapper.where(QUESTION.QUESTIONNAIRE_ID.eq(questionnaireId));
            queryWrapper.orderBy(QUESTION.SORT.desc());
            queryWrapper.limit(1);
            Question lastQuestion = questionMapper.selectOneByQuery(queryWrapper);
            int sort = 1;
            if (lastQuestion != null) {
                sort = lastQuestion.getSort() + 1;
            }
            question.setSort(sort);
        }

        // 设置创建人信息
//        question.setCreateBy(StpUtil.getLoginIdAsLong());

        // 构建选项列表
        List<Question.QuestionOption> options = new ArrayList<>();

        // 处理选项因子字符串（使用&&分割）A选项为空
        if (StrUtil.isNotBlank(excelData.getBetaj())) {
            String[] betajArray = excelData.getBetaj().split("&&");
            for (int i = 0; i < betajArray.length; i++) {
                String betajStr = betajArray[i];
                try {
                    Double betajValue = StrUtil.isBlank(betajStr) ? null : Double.parseDouble(betajStr);
                    Question.QuestionOption option = new Question.QuestionOption();
                    option.setId((long) (i + 1));
                    option.setBetaj(betajValue);
                    option.setSort(i + 1);
                    options.add(option);
                } catch (NumberFormatException e) {
                    log.warn("选项因子值解析失败: {}", betajStr);
                }
            }
        }

        question.setOptions(options);

        return question;
    }

    /**
     * 将Question对象转换为Excel数据格式
     */
    private ExcelQuestionDto convertQuestionToExcel(Question question, Map<Long, List<String>> optionMap) {
        List<String> optionList = optionMap.getOrDefault(question.getOptionCategoryId(), new ArrayList<>());
        ExcelQuestionDto excelData = ExcelQuestionDto.builder()
                .title(question.getTitle())
                .alphj(question.getAlphj())
                .sort(question.getSort())
                .optionCategory(StringUtils.join(optionList, ";"))
                .optionCategoryId(question.getOptionCategoryId())
                .build();

        // 处理选项数据，将选项因子值用&&连接
        if (!CollectionUtils.isEmpty(question.getOptions())) {
            List<Question.QuestionOption> options = question.getOptions();

            // 按照sort排序
            options.sort(Comparator.comparing(Question.QuestionOption::getSort));

            // 将选项因子值用&&连接
            StringBuilder betajBuilder = new StringBuilder();
            for (int i = 0; i < options.size(); i++) {
                Question.QuestionOption option = options.get(i);
                if (option.getBetaj() != null) {
                    if (i > 0) {
                        betajBuilder.append("&&");
                    }
                    betajBuilder.append(option.getBetaj());
                }
            }
            excelData.setBetaj(betajBuilder.toString());
        }

        return excelData;
    }

    /**
     * 将 QuestionOptionDTO 列表转换为 Question.QuestionOption 列表
     */
    private List<Question.QuestionOption> convertOptions(List<QuestionOptionDTO> optionDTOS) {
        if (CollectionUtils.isEmpty(optionDTOS)) {
            return new ArrayList<>();
        }

        List<Question.QuestionOption> options = new ArrayList<>();
        for (int i = 0; i < optionDTOS.size(); i++) {
            QuestionOptionDTO optionDTO = optionDTOS.get(i);

            // 创建选项
            Question.QuestionOption option = new Question.QuestionOption();
            BeanUtils.copyProperties(optionDTO, option);
            option.setSort(i + 1);

            options.add(option);
        }

        return options;
    }

    /**
     * 删除问卷题目缓存
     */
    private void deleteQuestionCache(Long questionnaireId) {
        String cacheKey = QUESTION_CACHE_KEY_PREFIX + questionnaireId;
        try {
            redisTemplate.delete(cacheKey);
            log.info("已删除问卷[{}]的题目缓存", questionnaireId);
        } catch (Exception e) {
            log.error("删除问卷[{}]题目缓存失败: {}", questionnaireId, e.getMessage());
        }
    }

} 